/**
 * 
 */
package org.jenkon.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * Class with utility helping methods for class handling.
 * 
 * @author jkonopka
 * 
 */
public final class ClassUtils {

	/**
	 * 
	 */
	private ClassUtils() {
	}

	/**
	 * @param obj the source object from who create the new instance
	 * @return the new instance of the parameter object
	 * @throws IllegalArgumentException error handling
	 */
	public static <T> T newInstance(final T obj) {
		return newInstance(obj.getClass());
	}

	/**
	 * @param obj the source {@link Class} from who create the new instance
	 * @return the new instance of the parameter {@link Class}
	 * @throws IllegalArgumentException error handling
	 */
	public static <T> T newInstance(final Class<?> clazz) {
		return newInstance(clazz.getName());
	}

	/**
	 * @param obj the source name of {@link Class} from who create the new instance
	 * @return the new instance of the parameter name of {@link Class}
	 * @throws IllegalArgumentException error handling
	 */
	@SuppressWarnings("unchecked")
	public static <T> T newInstance(final String name) {
		try {
			return (T) Class.forName(name).newInstance();
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	/**
	 * Check the {@link Class} of does existing a {@link Method} with the name.
	 * 
	 * @param clazz {@link Class} to check of existing method
	 * @param name the name of the {@link Method} to searching
	 * @return <code>true</code> if a {@link Method} with the name does exist in {@link Class} or
	 *         <code>false</code> if doesn't exist a {@link Method} with name in {@link Class}
	 */
	public static boolean hasMethod(final Class<?> clazz, final String name) {
		for (final Method method : clazz.getDeclaredMethods()) {
			if (method.getName().equals(name)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Check the {@link Class} of does existing a {@link Annotation} with the name.
	 * 
	 * @param clazz {@link Class} to check of existing {@link Annotation}
	 * @param annotation the {@link Annotation} to search
	 * @return <code>true</code> if a {@link Annotation} does exist in {@link Class} or
	 *         <code>false</code> if doesn't exist a {@link Annotation} in {@link Class}
	 */
	public static boolean hasAnnotation(final Class<?> clazz, final Class<? extends Annotation> annotation) {
		return (clazz.getAnnotation(annotation) != null);
	}

	/**
	 * Check the {@link Class} of does existing a {@link Annotation} with the name.
	 * 
	 * @param clazz {@link Class} to check of existing {@link Annotation}
	 * @param name the name of the {@link Annotation} to searching
	 * @return <code>true</code> if a {@link Annotation} with the name does exist in {@link Class}
	 *         or <code>false</code> if doesn't exist a {@link Annotation} with name in
	 *         {@link Class}
	 */
	public static boolean hasAnnotation(final Class<?> clazz, final String name) {
		for (final Annotation annotation : clazz.getAnnotations()) {
			if (annotation.annotationType().getName().equals(name)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @param left left object
	 * @param right right object
	 * @return true or false
	 */
	public static boolean isEquals(final Object left, final Object right) {
		return isEquals(left.getClass(), right.getClass());
	}

	/**
	 * @param left {@link Class}
	 * @param right {@link Class}
	 * @return true or false
	 */
	public static boolean isEquals(final Class<?> left, final Class<?> right) {
		return left == right;
	}

	/**
	 * @param clazz {@link Class}
	 * @param value the value object to check
	 * @return true or false
	 */
	public static boolean isInstance(final Class<?> clazz, final Object value) {
		return clazz.isInstance(value);
	}

}
